import cv2
import numpy as np
import os
import asyncio
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from typing import List, Tuple, Optional, Dict
import sys
from PIL import Image, ImageDraw, ImageFont
from pathlib import Path
import time
import logging
import traceback

from src.utils.style_manager import StyleManager
from src.utils.resource_helper import get_resource_path  # 导入资源加载函数
from config.settings import (
    APP_NAME,
    UI,
    IMAGE_RECOGNITION,
    MATCHING_METHODS,
    SPECIAL_TEMPLATES,
    ENABLE_PRINT,
)

# 添加项目根目录到路径
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))

# 导入配置
try:
    from config.settings import IMAGE_RECOGNITION, SPECIAL_TEMPLATES, MATCHING_METHODS
except ImportError:
    # 默认配置
    StyleManager.debug_print("警告：无法导入配置，使用默认值")
    # 默认配置在此移除，已经移至config/settings.py

# 中文字体路径 - 使用系统默认字体
FONT_PATH = os.path.join(os.environ.get("WINDIR", ""), "Fonts", "simhei.ttf")
if not os.path.exists(FONT_PATH):
    # 备用字体
    font_paths = [
        os.path.join(os.environ.get("WINDIR", ""), "Fonts", "msyh.ttc"),  # 微软雅黑
        os.path.join(os.environ.get("WINDIR", ""), "Fonts", "simsun.ttc"),  # 宋体
        "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf",  # Linux
        "/System/Library/Fonts/PingFang.ttc",  # macOS
    ]
    for path in font_paths:
        if os.path.exists(path):
            FONT_PATH = path
            break


class RecognitionResult:
    """
    图像识别结果类
    
    包含匹配结果的位置、尺寸、置信度和模板信息
    """
    
    def __init__(
        self,
        x: int,
        y: int,
        w: int,
        h: int,
        confidence: float,
        template_name: str,
        template_path: str,
        source_path: str,
        color_match: float = 0.0,
    ):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.confidence = confidence
        self.template_name = template_name
        self.template_path = template_path
        self.source_path = source_path
        self.color_match = color_match
        
    @property
    def top_left(self) -> Tuple[int, int]:
        """
        获取匹配区域的左上角坐标
        """
        return (self.x, self.y)
        
    @property
    def bottom_right(self) -> Tuple[int, int]:
        """
        获取匹配区域的右下角坐标
        """
        return (self.x + self.w, self.y + self.h)
        
    @property
    def width(self) -> int:
        """
        获取匹配区域的宽度
        """
        return self.w
        
    @property
    def height(self) -> int:
        """
        获取匹配区域的高度
        """
        return self.h
        
    @property
    def center(self) -> Tuple[int, int]:
        """
        获取匹配区域的中心点坐标
        """
        return (self.x + self.w // 2, self.y + self.h // 2)
        
    def __repr__(self) -> str:
        """
        返回结果的字符串表示
        """
        return (
            f"RecognitionResult(template='{self.template_name}', "
            f"pos=({self.x},{self.y}), size=({self.w},{self.h}), "
            f"confidence={self.confidence:.4f})"
        )


class ImageRecognizer:
    """图像识别工具类，提供基于OpenCV的模板匹配功能"""

    # 线程池执行器，用于执行耗时操作
    _executor = ThreadPoolExecutor(max_workers=4)

    # 颜色匹配阈值
    COLOR_MATCH_THRESHOLD = IMAGE_RECOGNITION.get("color_match_threshold", 0.45)

    # 特殊模板配置 - 已移至config/settings.py

    # 添加缓存字典，保存图片有效性检查结果
    _image_validity_cache = {}
    
    # 添加缓存字典，保存图片尺寸信息
    _image_size_cache = {}

    @staticmethod
    def is_valid_image(image_path: str) -> bool:
        """检查文件是否是有效的图片"""
        # 首先检查缓存中是否已有此图片的检查结果
        if image_path in ImageRecognizer._image_validity_cache:
            return ImageRecognizer._image_validity_cache[image_path]
            
        try:
            img = cv2.imread(image_path)
            result = img is not None and img.size > 0
            # 将结果存入缓存
            ImageRecognizer._image_validity_cache[image_path] = result
            return result
        except Exception:
            # 将结果存入缓存
            ImageRecognizer._image_validity_cache[image_path] = False
            return False

    @staticmethod
    async def is_valid_image_async(image_path: str) -> bool:
        """异步检查文件是否是有效的图片"""
        # 首先检查缓存中是否已有此图片的检查结果
        if image_path in ImageRecognizer._image_validity_cache:
            return ImageRecognizer._image_validity_cache[image_path]
            
        result = await asyncio.get_event_loop().run_in_executor(
            ImageRecognizer._executor, ImageRecognizer.is_valid_image, image_path
        )
        return result

    @staticmethod
    def get_image_size(image_path: str) -> Optional[Tuple[int, int]]:
        """获取图像的尺寸
        
        Args:
            image_path: 图像文件路径
            
        Returns:
            图像尺寸(宽度, 高度)的元组，如果图像无效返回None
        """
        # 首先检查缓存中是否已有此图片的尺寸信息
        if image_path in ImageRecognizer._image_size_cache:
            return ImageRecognizer._image_size_cache[image_path]
            
        # 使用资源路径获取文件的实际路径
        actual_path = get_resource_path(image_path)
        
        if not os.path.exists(actual_path):
            # 缓存无效结果
            ImageRecognizer._image_size_cache[image_path] = None
            return None
            
        try:
            # 使用PIL打开图像以获取尺寸
            with Image.open(actual_path) as img:
                size = img.size  # 返回(宽度, 高度)
                # 缓存结果
                ImageRecognizer._image_size_cache[image_path] = size
                return size
        except Exception as e:
            StyleManager.debug_print(f"获取图像尺寸时出错: {str(e)}")
            # 缓存无效结果
            ImageRecognizer._image_size_cache[image_path] = None
            return None

    @staticmethod
    async def get_image_size_async(image_path: str) -> Optional[Tuple[int, int]]:
        """异步获取图像的尺寸
        
        Args:
            image_path: 图像文件路径
            
        Returns:
            图像尺寸(宽度, 高度)的元组，如果图像无效返回None
        """
        # 首先检查缓存中是否已有此图片的尺寸信息
        if image_path in ImageRecognizer._image_size_cache:
            return ImageRecognizer._image_size_cache[image_path]
            
        # 使用线程池异步获取尺寸
        return await asyncio.get_event_loop().run_in_executor(
            ImageRecognizer._executor, ImageRecognizer.get_image_size, image_path
        )

    @staticmethod
    def recognize_template(
        source_image_path: str,
        template_path: str,
        method: str = IMAGE_RECOGNITION["default_method"],
        threshold: float = IMAGE_RECOGNITION["default_threshold"],
        template_name: str = None,
    ) -> RecognitionResult:
        """
        在源图像中识别模板图像，支持多尺度匹配
        
        Args:
            source_image_path: 源图像路径
            template_path: 模板图像路径
            method: 匹配方法
            threshold: 置信度阈值
            template_name: 模板名称，为None时使用模板文件名
            
        Returns:
            匹配结果，如果没有匹配则返回None
        """
        # 记录函数开始时间，用于性能分析
        start_time = time.time()
        
        # 使用资源路径获取源图像和模板图像的实际路径
        actual_source_path = get_resource_path(source_image_path)
        actual_template_path = get_resource_path(template_path)
        
        # 检查源图像和模板图像是否存在
        if not os.path.exists(actual_source_path) or not os.path.exists(actual_template_path):
            return None
        # 读取源图像和模板图像
        img = cv2.imread(actual_source_path)
        template = cv2.imread(actual_template_path)
        
        if img is None or template is None:
            return None
            
        # 设置模板名称，默认使用模板文件名
        if template_name is None:
            template_name = os.path.basename(template_path)
        
        # 获取模板文件名，用于特殊模板匹配
        template_filename = os.path.basename(template_path)
        
        # 使用特殊模板配置（如果存在）
        special_threshold = threshold
        special_scales = None
        if template_filename in SPECIAL_TEMPLATES:
            special_config = SPECIAL_TEMPLATES[template_filename]
            special_threshold = special_config.get("confidence_threshold", threshold)
            special_scales = special_config.get("scales", None)
            StyleManager.debug_print(f"应用特殊模板配置 {template_filename}: 置信度阈值={special_threshold}")
            
        # 获取图像和模板的尺寸
        img_height, img_width = img.shape[:2]
        template_height, template_width = template.shape[:2]
        
        # 选择匹配方法
        match_method = getattr(cv2, method)
        
        # 获取缩放列表，特殊模板配置的scales优先级更高
        scales = special_scales if special_scales else IMAGE_RECOGNITION.get("scales", [1.0])
        StyleManager.debug_print(f"使用缩放比例列表: {scales}")
        
        # 最佳匹配结果
        best_confidence = 0.0 if method not in ["TM_SQDIFF", "TM_SQDIFF_NORMED"] else 1.0
        best_scale = 1.0
        best_location = None
        best_min_val = 1.0
        best_max_val = 0.0
        match_count = 0
        
        # 遍历不同缩放比例进行模板匹配
        for scale in scales:
            # 缩放模板
            if scale != 1.0:
                scaled_width = int(template_width * scale)
                scaled_height = int(template_height * scale)
                
                # 确保缩放后的尺寸不为零
                if scaled_width <= 0 or scaled_height <= 0:
                    continue
                    
                # 确保缩放后的模板不大于源图像
                if scaled_width > img_width or scaled_height > img_height:
                    StyleManager.debug_print(f"跳过过大的缩放比例 {scale:.2f}，缩放后尺寸 ({scaled_width}x{scaled_height}) 大于源图像 ({img_width}x{img_height})")
                    continue
                    
                # 缩放模板
                scaled_template = cv2.resize(template, (scaled_width, scaled_height), interpolation=cv2.INTER_AREA if scale < 1.0 else cv2.INTER_LINEAR)
            else:
                scaled_template = template
                scaled_width = template_width
                scaled_height = template_height
            
            # 执行模板匹配
            result = cv2.matchTemplate(img, scaled_template, match_method)
            
            # 获取匹配结果
            min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
            match_count += 1
            
            # 根据匹配方法确定匹配位置和置信度
            if method in ["TM_SQDIFF", "TM_SQDIFF_NORMED"]:
                top_left = min_loc
                confidence = 1 - min_val  # 转换为置信度
                
                # 检查是否超过阈值
                if min_val > 1 - special_threshold:
                    StyleManager.debug_print(f"缩放比例 {scale:.2f} 未达到阈值要求: {min_val:.4f} > {1-special_threshold:.4f}")
                    continue
                
                # 打印匹配值信息
                StyleManager.debug_print(f"模板匹配结果 - 模板: {template_filename}, 缩放: {scale:.2f}, 最小值: {min_val:.4f} (置信度: {confidence:.4f}), 阈值: {special_threshold}")
                
                # 检查是否优于当前最佳结果（对于SQDIFF方法，较小的min_val更好）
                if min_val < best_min_val:
                    best_min_val = min_val
                    best_confidence = confidence
                    best_location = top_left
                    best_scale = scale
                    StyleManager.debug_print(f"更新最佳匹配 - 缩放: {scale:.2f}, 置信度: {confidence:.4f}")
            else:
                top_left = max_loc
                confidence = max_val
                
                # 检查是否超过阈值
                if max_val < special_threshold:
                    StyleManager.debug_print(f"缩放比例 {scale:.2f} 未达到阈值要求: {max_val:.4f} < {special_threshold:.4f}")
                    continue
                
                # 打印匹配值信息
                StyleManager.debug_print(f"模板匹配结果 - 模板: {template_filename}, 缩放: {scale:.2f}, 最大值: {max_val:.4f} (置信度: {confidence:.4f}), 阈值: {special_threshold}")
                
                # 检查是否优于当前最佳结果（对于其他方法，较大的max_val更好）
                if max_val > best_max_val:
                    best_max_val = max_val
                    best_confidence = confidence
                    best_location = top_left
                    best_scale = scale
                    StyleManager.debug_print(f"更新最佳匹配 - 缩放: {scale:.2f}, 置信度: {confidence:.4f}")
        
        # 计算匹配耗时
        elapsed_time = time.time() - start_time
        
        # 使用最佳匹配创建识别结果
        if best_location is not None:
            x, y = best_location
            w = int(template_width * best_scale)
            h = int(template_height * best_scale)
            
            StyleManager.debug_print(f"找到最佳匹配 - 模板: {template_filename}, 尝试缩放数: {match_count}, 最佳缩放: {best_scale:.2f}, 置信度: {best_confidence:.4f}, 耗时: {elapsed_time:.3f}秒")
            
            # # 计算颜色匹配度
            # color_start_time = time.time()
            # if best_scale != 1.0:
            #     # 对于缩放后的模板，重新计算颜色匹配
            #     scaled_template = cv2.resize(template, (w, h), interpolation=cv2.INTER_AREA if best_scale < 1.0 else cv2.INTER_LINEAR)
            #     color_match = ImageRecognizer.verify_color_match(img, scaled_template, (x, y, w, h), template_name)
            # else:
            #     color_match = ImageRecognizer.verify_color_match(img, template, (x, y, w, h), template_name)
                
            # color_elapsed_time = time.time() - color_start_time
            # StyleManager.debug_print(f"颜色匹配计算耗时: {color_elapsed_time:.3f}秒, 匹配度: {color_match:.4f}")
            
            # 创建并返回匹配结果
            return RecognitionResult(
                x=x,
                y=y,
                w=w,
                h=h,
                confidence=best_confidence,
                template_name=template_name,
                template_path=template_path,
                source_path=source_image_path
                # color_match=color_match,  # 添加颜色匹配度
            )
        else:
            StyleManager.debug_print(f"未找到匹配 - 模板: {template_filename}, 尝试缩放数: {match_count}, 耗时: {elapsed_time:.3f}秒")
        
        return None

    @staticmethod
    async def recognize_template_async(
        source_image_path: str,
        template_path: str,
        method: str = IMAGE_RECOGNITION["default_method"],
        threshold: float = IMAGE_RECOGNITION["default_threshold"],
        template_name: str = None,
    ) -> RecognitionResult:
        """
        异步版本：在源图像中识别模板图像
        
        Args:
            source_image_path: 源图像路径
            template_path: 模板图像路径
            method: 匹配方法
            threshold: 置信度阈值
            template_name: 模板名称，为None时使用模板文件名
            
        Returns:
            匹配结果，如果没有匹配则返回None
        """
        # 注意：source_image_path应该已经是通过get_resource_path处理过的实际路径
        # 这里再次处理template_path，确保它是实际路径
        actual_template_path = get_resource_path(template_path)
        
        # 检查模板图像是否存在
        if not os.path.exists(actual_template_path):
            return None
            
        # 调用同步方法
        # 使用线程池执行IO密集型操作，避免阻塞事件循环
        loop = asyncio.get_running_loop()
        result = await loop.run_in_executor(
            None,
            ImageRecognizer.recognize_template,
            source_image_path,
            template_path,
            method,
            threshold,
            template_name,
        )       
        return result

    @staticmethod
    async def recognize_multiple_templates_async(
        source_image_path: str,
        template_paths: List[str],
        method: str = IMAGE_RECOGNITION["default_method"],
        threshold: float = IMAGE_RECOGNITION["default_threshold"],
        template_names: Dict[str, str] = None,
    ) -> List[RecognitionResult]:
        """
        异步版本：识别源图像中的多个模板
        
        Args:
            source_image_path: 源图像路径
            template_paths: 模板图像路径列表
            method: 匹配方法
            threshold: 置信度阈值
            template_names: 模板名称字典，键为模板路径，值为模板名称
            
        Returns:
            匹配结果列表，按置信度降序排序
        """
        # 使用资源路径获取源图像的实际路径
        actual_source_path = get_resource_path(source_image_path)
        
        if not os.path.exists(actual_source_path):
            return []
            
        # 获取源图像信息，方便调试
        img = cv2.imread(actual_source_path)
        if img is not None:
            StyleManager.debug_print(f"源图像尺寸: {img.shape[1]}x{img.shape[0]}")
        
        tasks = []
        for template_path in template_paths:
            # 注意：template_path可能已经是通过get_resource_path处理过的
            # 获取模板名称
            if template_names and template_path in template_names:
                template_name = template_names[template_path]
            else:
                template_name = os.path.basename(template_path)
                
            # 获取模板文件名用于特殊处理
            template_filename = os.path.basename(template_path)
            
            # 对特殊模板应用特定处理
            current_threshold = threshold
            if template_filename in SPECIAL_TEMPLATES:
                special_config = SPECIAL_TEMPLATES[template_filename]
                current_threshold = special_config.get("confidence_threshold", threshold)
                StyleManager.debug_print(f"对模板 {template_filename} ({template_name}) 应用特殊阈值: {current_threshold}")
                
            # 添加识别任务
            task = ImageRecognizer.recognize_template_async(
                actual_source_path, template_path, method, current_threshold, template_name
            )
            tasks.append(task)
            
        # 并行执行所有任务
        results = []
        for future in asyncio.as_completed(tasks):
            result = await future
            if result:
                results.append(result)
                
        # 输出找到的结果数量和模板名称
        if results:
            result_names = [result.template_name for result in results]
            StyleManager.debug_print(f"找到 {len(results)} 个匹配结果: {', '.join(result_names)}")
        else:
            StyleManager.debug_print("未找到任何匹配结果")
        
        # # 使用颜色匹配度进行过滤
        # filtered_results = []
        # for result in results:
        #     template_filename = os.path.basename(result.template_path)
        #     color_threshold = ImageRecognizer.COLOR_MATCH_THRESHOLD
            
        #     # 获取特殊模板的颜色阈值（如果存在）
        #     if template_filename in SPECIAL_TEMPLATES:
        #         special_config = SPECIAL_TEMPLATES[template_filename]
        #         color_threshold = special_config.get("color_threshold", color_threshold)
                
        #     # 检查颜色匹配度是否达到阈值
        #     if result.color_match >= color_threshold:
        #         filtered_results.append(result)
        #     else:
        #         StyleManager.debug_print(f"由于颜色匹配度不足，过滤掉结果: {template_filename}, 颜色匹配度: {result.color_match:.2f} < {color_threshold}")
                
        # # 按置信度降序排序
        # filtered_results.sort(key=lambda x: x.confidence, reverse=True)
        
        # # 输出过滤后的结果数量
        # if filtered_results:
        #     StyleManager.debug_print(f"颜色过滤后剩余 {len(filtered_results)} 个匹配结果")
        
        # return filtered_results
        return results

    @staticmethod
    def cv2_img_add_text(
        img, text, left, top, text_color=(255, 255, 255), text_size=20
    ):
        """
        在OpenCV图像上添加中文文本
        使用PIL绘制文本，然后转换回OpenCV格式

        参数:
            img: OpenCV图像
            text: 文本内容
            left, top: 文本位置
            text_color: 文本颜色
            text_size: 文本大小

        返回:
            添加文本后的图像
        """
        if isinstance(img, np.ndarray):
            # OpenCV图像转为PIL图像
            img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

        # 创建绘图对象
        draw = ImageDraw.Draw(img)

        # 使用系统字体，支持中文
        try:
            font = ImageFont.truetype(FONT_PATH, text_size)
        except IOError:
            # 如果无法加载字体，使用默认字体
            font = ImageFont.load_default()

        # 绘制文本
        draw.text((left, top), text, text_color, font=font)

        # PIL图像转回OpenCV格式
        return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)

    @staticmethod
    def visualize_results(
        source_image_path: str,
        results: List[RecognitionResult],
        output_path: str = None,
    ) -> np.ndarray:
        """
        可视化识别结果，绘制边框和置信度
        
        Args:
            source_image_path: 源图像路径 (已经是通过get_resource_path处理过的实际路径)
            results: 识别结果列表
            output_path: 输出图像路径，如果为None则不保存
            
        Returns:
            处理后的图像数组
        """
        # 假定传入的source_image_path已经是实际路径
        img = cv2.imread(source_image_path)
        if img is None:
            StyleManager.debug_print(f"无法读取图像: {source_image_path}")
            return None
            
        # 复制一份图像用于绘制
        img_copy = img.copy()
        
        # 定义颜色和线条属性
        color = (0, 255, 0)  # 绿色
        thickness = 2
        font = cv2.FONT_HERSHEY_SIMPLEX
        font_scale = 0.6
        font_thickness = 1
        
        # 对每个结果绘制边框和置信度
        for result in results:
            # 绘制矩形
            cv2.rectangle(
                img_copy,
                (result.x, result.y),
                (result.x + result.w, result.y + result.h),
                color,
                thickness,
            )
            
            # 计算置信度文本和位置
            text = f"{result.template_name}: {result.confidence:.2f}"
            text_size = cv2.getTextSize(text, font, font_scale, font_thickness)[0]
            text_x = result.x
            text_y = result.y - 10  # 在矩形上方显示文本
            
            # 如果文本超出了图像上边界，则将文本放在矩形内部顶部
            if text_y < text_size[1]:
                text_y = result.y + text_size[1] + 5
                
            # 绘制置信度文本
            cv2.putText(
                img_copy,
                text,
                (text_x, text_y),
                font,
                font_scale,
                color,
                font_thickness,
                cv2.LINE_AA,
            )
            
        # 如果指定了输出路径，保存图像
        if output_path:
            try:
                cv2.imwrite(output_path, img_copy)
                StyleManager.debug_print(f"已保存结果图像到: {output_path}")
            except Exception as e:
                StyleManager.debug_print(f"保存结果图像时出错: {str(e)}")
                
        return img_copy

    @staticmethod
    async def visualize_results_async(
        source_image_path: str,
        results: List[RecognitionResult],
        output_path: str = None,
    ) -> np.ndarray:
        """
        异步版本：可视化识别结果
        """
        return await asyncio.get_event_loop().run_in_executor(
            ImageRecognizer._executor,
            ImageRecognizer.visualize_results,
            source_image_path,
            results,
            output_path,
        )

    @staticmethod
    def draw_recognition_results(
        source_image_path: str,
        results: List[RecognitionResult],
        output_path: str = None,
    ) -> np.ndarray:
        """
        可视化识别结果，绘制边框和置信度
        
        Args:
            source_image_path: 源图像路径
            results: 识别结果列表
            output_path: 输出图像路径，如果为None则不保存
            
        Returns:
            处理后的图像数组
        """
        # 使用资源路径获取源图像的实际路径
        actual_source_path = get_resource_path(source_image_path)
        
        # 检查源图像是否存在
        if not os.path.exists(actual_source_path) or not results:
            return None
            
        try:
            # 调用可视化方法
            return ImageRecognizer.visualize_results(
                actual_source_path, results, output_path
            )
        except Exception as e:
            StyleManager.debug_print(f"绘制识别结果时出错: {str(e)}")
            return None

    @staticmethod
    async def draw_recognition_results_async(
        source_image_path: str,
        results: List[RecognitionResult],
        output_path: str = None,
    ) -> np.ndarray:
        """
        异步版本：绘制识别结果，与visualize_results_async相同，保留向后兼容性
        """
        return await ImageRecognizer.visualize_results_async(
            source_image_path, results, output_path
        )

    @staticmethod
    def verify_color_match(source_img, template_img, location, template_name=None):
        """验证匹配区域的颜色是否与模板颜色匹配

        参数:
            source_img: 源图像
            template_img: 模板图像
            location: 匹配位置 (x, y, w, h)
            template_name: 模板名称，用于特殊处理

        返回:
            匹配度分数，0-1之间的值，1表示完全匹配
        """
        x, y, w, h = location

        # 提取匹配区域
        region = source_img[y : y + h, x : x + w]

        # 如果区域大小不匹配模板大小，可能超出源图像边界
        if (
            region.shape[0] != template_img.shape[0]
            or region.shape[1] != template_img.shape[1]
        ):
            # 返回最小可能的区域，但不为0
            return 0.01

        # 计算直方图
        def calculate_histogram(img):
            # 降低直方图bin数量，使匹配更宽松
            hist_b = cv2.calcHist([img], [0], None, [32], [0, 256])
            hist_g = cv2.calcHist([img], [1], None, [32], [0, 256])
            hist_r = cv2.calcHist([img], [2], None, [32], [0, 256])

            # 归一化
            cv2.normalize(hist_b, hist_b, 0, 1, cv2.NORM_MINMAX)
            cv2.normalize(hist_g, hist_g, 0, 1, cv2.NORM_MINMAX)
            cv2.normalize(hist_r, hist_r, 0, 1, cv2.NORM_MINMAX)

            return hist_b, hist_g, hist_r

        # 计算直方图
        region_hist_b, region_hist_g, region_hist_r = calculate_histogram(region)
        template_hist_b, template_hist_g, template_hist_r = calculate_histogram(
            template_img
        )

        # 比较直方图
        score_b = cv2.compareHist(region_hist_b, template_hist_b, cv2.HISTCMP_CORREL)
        score_g = cv2.compareHist(region_hist_g, template_hist_g, cv2.HISTCMP_CORREL)
        score_r = cv2.compareHist(region_hist_r, template_hist_r, cv2.HISTCMP_CORREL)

        # 提取文件名(若有路径)
        if template_name is None:
            template_name = ""

        base_filename = os.path.basename(template_name) if template_name else ""

        # 打印调试信息
        StyleManager.debug_print(
            f"颜色匹配分数: B={score_b:.2f}, G={score_g:.2f}, R={score_r:.2f}, 模板:{base_filename}"
        )

        # 使用特殊模板配置中的颜色阈值（如果存在）
        color_threshold = ImageRecognizer.COLOR_MATCH_THRESHOLD
        if base_filename in SPECIAL_TEMPLATES:
            special_config = SPECIAL_TEMPLATES[base_filename]
            color_threshold = special_config.get("color_threshold", color_threshold)
            StyleManager.debug_print(f"应用特殊模板颜色阈值配置 {base_filename}: 颜色阈值={color_threshold}")
        
        # 计算区域和模板的颜色特征
        region_features = ImageRecognizer.calculate_color_features(region)
        template_features = ImageRecognizer.calculate_color_features(template_img)
        
        # 针对特定模板的颜色特征分析
        if "power.png" in base_filename:
            # power.png的特点是红色较明显
            avg_score = (score_b * 0.8 + score_g * 1.0 + score_r * 1.2) / 3.0
            
            # 如果区域的红色主导性与模板接近或更高，提高评分
            if region_features['red_dominance'] >= template_features['red_dominance'] * 0.8:
                avg_score = min(1.0, avg_score * 1.15)  # 提高15%的匹配度
                StyleManager.debug_print(
                    f"power.png红色增强: 区域={region_features['red_dominance']:.2f}, "
                    f"模板={template_features['red_dominance']:.2f}, 调整后分数: {avg_score:.2f}"
                )

        elif "gold.png" in base_filename:
            # gold.png的特点是黄色较明显（红+绿高，蓝低）
            yellow_score = min(
                region_features['yellow_dominance'] / max(0.01, template_features['yellow_dominance']),
                2.0
            )
            
            if yellow_score > 0.8 and region_features['b_ratio'] < 0.32:
                # 对金币使用更严格的颜色匹配逻辑
                avg_score = (score_r * 1.2 + score_g * 1.2) / (score_b * 0.8 + 2.4) * yellow_score
                avg_score = min(0.85, avg_score)  # 金币匹配度不超过0.85，防止误匹配
                StyleManager.debug_print(f"gold.png黄色增强: 黄色得分={yellow_score:.2f}, 调整后分数: {avg_score:.2f}")
            else:
                # 普通加权
                avg_score = (score_b * 0.5 + score_g * 1.2 + score_r * 1.0) / 2.7
                
        elif "wood.png" in base_filename:
            # 木材的特点是棕色（红绿高，蓝低）
            brown_score = min(
                region_features['brown_dominance'] / max(0.01, template_features['brown_dominance']),
                2.0
            )
            
            if brown_score > 0.7:
                avg_score = (score_b * 0.5 + score_g * 1.4 + score_r * 1.3) / 3.2 * brown_score
            else:
                avg_score = (score_b * 0.6 + score_g * 1.5 + score_r * 1.2) / 3.3
                
            StyleManager.debug_print(f"wood.png特殊处理: 棕色得分={brown_score:.2f}, 调整后分数: {avg_score:.2f}")
            
        elif "ice.png" in base_filename:
            # 冰的特点是蓝色较明显
            blue_score = min(
                region_features['blue_dominance'] / max(0.01, template_features['blue_dominance']),
                2.0
            )
            
            if blue_score > 0.7:
                avg_score = (score_b * 1.6 + score_g * 0.8 + score_r * 0.6) / 3.0 * blue_score
            else:
                avg_score = (score_b * 1.5 + score_g * 1.0 + score_r * 0.7) / 3.2
                
            StyleManager.debug_print(f"ice.png特殊处理: 蓝色得分={blue_score:.2f}, 调整后分数: {avg_score:.2f}")
            
        elif "mana.png" in base_filename:
            # 魔法的特点是紫色或蓝紫色
            purple_score = min(
                region_features['purple_dominance'] / max(0.01, template_features['purple_dominance']),
                2.0
            )
            blue_score = min(
                region_features['blue_dominance'] / max(0.01, template_features['blue_dominance']),
                2.0
            )
            
            color_score = max(purple_score, blue_score)
            if color_score > 0.7:
                avg_score = (score_b * 1.3 + score_g * 0.7 + score_r * 1.1) / 3.1 * color_score
            else:
                avg_score = (score_b * 1.3 + score_g * 0.8 + score_r * 1.1) / 3.2
                
            StyleManager.debug_print(f"mana.png特殊处理: 紫色得分={purple_score:.2f}, 蓝色得分={blue_score:.2f}, 调整后分数: {avg_score:.2f}")
            
        elif "glove.png" in base_filename:
            # 手套颜色可能多样，使用亮度和饱和度比较
            brightness_diff = abs(region_features['brightness'] - template_features['brightness']) / 255.0
            saturation_diff = abs(region_features['saturation'] - template_features['saturation']) / 255.0
            
            # 亮度和饱和度差异小意味着更好的匹配
            color_similarity = 1.0 - (brightness_diff * 0.6 + saturation_diff * 0.4)
            avg_score = (score_b * 0.9 + score_g * 1.2 + score_r * 1.0) / 3.1 * color_similarity
            
            StyleManager.debug_print(f"glove.png特殊处理: 亮度差={brightness_diff:.2f}, 饱和度差={saturation_diff:.2f}, 颜色相似度={color_similarity:.2f}, 调整后分数: {avg_score:.2f}")
            
        elif "belt.png" in base_filename:
            # 腰带可能包含金属部分，对比红绿蓝标准差差异
            std_diff = (
                abs(region_features['r_std'] - template_features['r_std']) / max(template_features['r_std'], 1.0) +
                abs(region_features['g_std'] - template_features['g_std']) / max(template_features['g_std'], 1.0) +
                abs(region_features['b_std'] - template_features['b_std']) / max(template_features['b_std'], 1.0)
            ) / 3.0
            
            # 标准差差异小意味着纹理更相似
            texture_similarity = 1.0 - min(std_diff, 1.0)
            avg_score = (score_b * 0.8 + score_g * 1.1 + score_r * 1.1) / 3.0 * (0.7 + 0.3 * texture_similarity)
            
            StyleManager.debug_print(f"belt.png特殊处理: 标准差差异={std_diff:.2f}, 纹理相似度={texture_similarity:.2f}, 调整后分数: {avg_score:.2f}")
            
        else:
            # 其他模板使用标准权重
            avg_score = (score_b + score_g * 1.5 + score_r) / 3.5

        # 确保得分在有效范围内，但如果颜色匹配度低于阈值，则降低分数
        avg_score = max(0.01, min(1.0, avg_score))
        
        # 如果颜色匹配度低于阈值但不为零，给出警告
        if 0.01 < avg_score < color_threshold:
            StyleManager.debug_print(f"警告: {base_filename} 颜色匹配度 {avg_score:.2f} 低于阈值 {color_threshold}")

        return avg_score

    @staticmethod
    def calculate_red_dominance(image):
        """计算图像中红色的显著性

        参数:
            image: OpenCV BGR图像

        返回:
            红色显著性分数 (0-1)
        """
        # 将图像分割为BGR通道
        b, g, r = cv2.split(image)

        # 计算红色超过其他通道的区域
        red_mask = np.logical_and(r > b + 30, r > g + 30).astype(np.uint8) * 255

        # 计算红色区域占比
        red_ratio = np.sum(red_mask) / (red_mask.shape[0] * red_mask.shape[1] * 255)

        return red_ratio

    @staticmethod
    def calculate_color_features(image):
        """计算图像的颜色特征

        参数:
            image: OpenCV BGR图像

        返回:
            包含颜色特征的字典
        """
        # 将图像分割为BGR通道
        b, g, r = cv2.split(image)
        
        # 计算各通道的平均值和标准差
        b_mean, b_std = np.mean(b), np.std(b)
        g_mean, g_std = np.mean(g), np.std(g)
        r_mean, r_std = np.mean(r), np.std(r)
        
        # 计算亮度（灰度均值）
        brightness = np.mean(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY))
        
        # 计算饱和度
        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        h, s, v = cv2.split(hsv)
        saturation_mean = np.mean(s)
        
        # 计算各通道比例
        total = b_mean + g_mean + r_mean
        if total > 0:
            b_ratio = b_mean / total
            g_ratio = g_mean / total
            r_ratio = r_mean / total
        else:
            b_ratio = g_ratio = r_ratio = 0.333
            
        # 计算红色、黄色、绿色、蓝色的主导程度
        red_dominance = ImageRecognizer.calculate_red_dominance(image)
        
        # 黄色 = 红+绿多，蓝少
        yellow_mask = np.logical_and(
            np.logical_and(r > b + 30, g > b + 30),
            np.abs(r - g) < 30
        ).astype(np.uint8) * 255
        yellow_dominance = np.sum(yellow_mask) / (yellow_mask.shape[0] * yellow_mask.shape[1] * 255)
        
        # 绿色 = 绿通道明显高于红和蓝
        green_mask = np.logical_and(
            g > r + 30,
            g > b + 30
        ).astype(np.uint8) * 255
        green_dominance = np.sum(green_mask) / (green_mask.shape[0] * green_mask.shape[1] * 255)
        
        # 蓝色 = 蓝通道明显高于红和绿
        blue_mask = np.logical_and(
            b > r + 30,
            b > g + 30
        ).astype(np.uint8) * 255
        blue_dominance = np.sum(blue_mask) / (blue_mask.shape[0] * blue_mask.shape[1] * 255)
        
        # 棕色 = 红略高于绿，两者都明显高于蓝
        brown_mask = np.logical_and(
            np.logical_and(r > b + 30, g > b + 30),
            r > g + 10
        ).astype(np.uint8) * 255
        brown_dominance = np.sum(brown_mask) / (brown_mask.shape[0] * brown_mask.shape[1] * 255)
        
        # 紫色 = 红和蓝较高，绿较低
        purple_mask = np.logical_and(
            np.logical_and(r > g + 30, b > g + 30),
            np.abs(r - b) < 50
        ).astype(np.uint8) * 255
        purple_dominance = np.sum(purple_mask) / (purple_mask.shape[0] * purple_mask.shape[1] * 255)
        
        return {
            'b_mean': b_mean,
            'g_mean': g_mean,
            'r_mean': r_mean,
            'b_std': b_std,
            'g_std': g_std,
            'r_std': r_std,
            'brightness': brightness,
            'saturation': saturation_mean,
            'b_ratio': b_ratio,
            'g_ratio': g_ratio,
            'r_ratio': r_ratio,
            'red_dominance': red_dominance,
            'yellow_dominance': yellow_dominance,
            'green_dominance': green_dominance,
            'blue_dominance': blue_dominance,
            'brown_dominance': brown_dominance,
            'purple_dominance': purple_dominance
        }

